package library;

import library.utils.Utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import library.model.Genre;
import library.tree.GenresTreeNode;

/**
 * @author sad
 */
public class GenresTree extends JTree {
    private Map<Genre, List<Genre>> fullList = new TreeMap<>();
    private ArrayList<String> filter = new ArrayList<>();
    private OnGenreSelected event;

    public static interface OnGenreSelected {
        public void genreSelected(String genreId);
    }

    public GenresTree() {
        setFont(Utils.getDefaultFont());
        setRowHeight(20);
        fillFullList();
        setShowsRootHandles(true);
        setRootVisible(false);
        clearNodes();

        addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                Object obj = e.getPath().getLastPathComponent();
                if (obj != null && obj instanceof GenresTreeNode) {
                    GenresTreeNode node = (GenresTreeNode) obj;
                    if (event != null) {
                        event.genreSelected(node.getId());
                    }
                }
            }
        });
    }

    public void setGenreSelectedEvent(OnGenreSelected event) {
        this.event = event;
    }

    private void fillFullList() {
        Genre g;
        g = new Genre("1", "Фантастика");
        addGenre(g, new Genre("11", "Альтернативная история"));
        addGenre(g, new Genre("12", "Боевая фантастика"));
        addGenre(g, new Genre("13", "Эпическая фантастика"));
        addGenre(g, new Genre("14", "Героическая фантастика"));
        addGenre(g, new Genre("15", "Детективная фантастика"));
        addGenre(g, new Genre("16", "Киберпанк"));
        addGenre(g, new Genre("17", "Космическая фантастика"));
        addGenre(g, new Genre("18", "Социально-психологическая фантастика"));
        addGenre(g, new Genre("19", "Ужасы и Мистика"));
        addGenre(g, new Genre("1A", "Юмористическая фантастика"));
        addGenre(g, new Genre("1B", "Фэнтези"));
        addGenre(g, new Genre("10", "Научная Фантастика"));

        g = new Genre("2", "Детективы и Триллеры");
        addGenre(g, new Genre("21", "Классический детектив"));
        addGenre(g, new Genre("22", "Полицейский детектив"));
        addGenre(g, new Genre("23", "Боевик"));
        addGenre(g, new Genre("24", "Иронический детектив"));
        addGenre(g, new Genre("25", "сторический детектив"));
        addGenre(g, new Genre("26", "Шпионский детектив"));
        addGenre(g, new Genre("27", "Криминальный детектив"));
        addGenre(g, new Genre("28", "Политический детектив"));
        addGenre(g, new Genre("29", "Маньяки"));
        addGenre(g, new Genre("2A", "Крутой детектив"));
        addGenre(g, new Genre("2B", "Триллер"));
        addGenre(g, new Genre("20", "Детектив"));

        g = new Genre("3", "Проза");
        addGenre(g, new Genre("31", "Классическая проза"));
        addGenre(g, new Genre("32", "Историческая проза"));
        addGenre(g, new Genre("33", "Современная проза"));
        addGenre(g, new Genre("34", "Контркультура"));
        addGenre(g, new Genre("35", "Русская классическая проза"));
        addGenre(g, new Genre("36", "Советская классическая проза"));
        addGenre(g, new Genre("37", "Военная проза"));
        addGenre(g, new Genre("30", "Проза"));

        g = new Genre("4", "Любовные романы");
        addGenre(g, new Genre("41", "Современные любовные романы"));
        addGenre(g, new Genre("42", "Исторические любовные романы"));
        addGenre(g, new Genre("43", "Остросюжетные любовные романы"));
        addGenre(g, new Genre("44", "Короткие любовные романы"));
        addGenre(g, new Genre("45", "Эротика"));
        addGenre(g, new Genre("46", "Любовная фантастика"));
        addGenre(g, new Genre("40", "Любовные романы"));

        g = new Genre("5", "Приключения");
        addGenre(g, new Genre("51", "Вестерн"));
        addGenre(g, new Genre("52", "Исторические приключения"));
        addGenre(g, new Genre("53", "Приключения про индейцев"));
        addGenre(g, new Genre("54", "Морские приключения"));
        addGenre(g, new Genre("55", "Путешествия и география"));
        addGenre(g, new Genre("56", "Природа и животные"));
        addGenre(g, new Genre("50", "Приключения"));

        g = new Genre("6", "Детская литература");
        addGenre(g, new Genre("61", "Сказка"));
        addGenre(g, new Genre("62", "Детские стихи"));
        addGenre(g, new Genre("63", "Детская проза"));
        addGenre(g, new Genre("64", "Детская фантастика"));
        addGenre(g, new Genre("65", "Детские остросюжетные"));
        addGenre(g, new Genre("66", "Детские приключения"));
        addGenre(g, new Genre("67", "Детская образовательная литература"));
        addGenre(g, new Genre("60", "Детская литература"));

        g = new Genre("7", "Поэзия, Драматургия");
        addGenre(g, new Genre("71", "Поэзия"));
        addGenre(g, new Genre("72", "Драматургия"));

        g = new Genre("8", "Старинное");
        addGenre(g, new Genre("81", "Античная литература"));
        addGenre(g, new Genre("82", "Европейская старинная литература"));
        addGenre(g, new Genre("83", "Древнерусская литература"));
        addGenre(g, new Genre("84", "Древневосточная литература"));
        addGenre(g, new Genre("85", "Мифы. Легенды. Эпос."));
        addGenre(g, new Genre("80", "Старинная литература"));

        g = new Genre("9", "Наука, Образование");
        addGenre(g, new Genre("91", "История"));
        addGenre(g, new Genre("92", "Психология"));
        addGenre(g, new Genre("93", "Культурология"));
        addGenre(g, new Genre("94", "Религиоведение"));
        addGenre(g, new Genre("95", "Философия"));
        addGenre(g, new Genre("96", "Политика"));
        addGenre(g, new Genre("97", "Деловая литература"));
        addGenre(g, new Genre("98", "Юриспруденция"));
        addGenre(g, new Genre("99", "Языкознание"));
        addGenre(g, new Genre("9A", "Медицина"));
        addGenre(g, new Genre("9B", "Физика"));
        addGenre(g, new Genre("9C", "Математика"));
        addGenre(g, new Genre("9D", "Химия"));
        addGenre(g, new Genre("9E", "Биология"));
        addGenre(g, new Genre("9F", "Технические науки"));
        addGenre(g, new Genre("90", "Научная литература"));

        g = new Genre("A", "Компьютеры и Интернет");
        addGenre(g, new Genre("A1", "Интернет"));
        addGenre(g, new Genre("A2", "Программирование"));
        addGenre(g, new Genre("A3", "Компьютерное железо (аппаратное обеспечение)"));
        addGenre(g, new Genre("A4", "Программы"));
        addGenre(g, new Genre("A5", "Базы данных"));
        addGenre(g, new Genre("A6", "ОС и Сети"));
        addGenre(g, new Genre("A0", "Компьтерная литература"));

        g = new Genre("B", "Справочная литература");
        addGenre(g, new Genre("B1", "Энциклопедии"));
        addGenre(g, new Genre("B2", "Словари"));
        addGenre(g, new Genre("B3", "Справочники"));
        addGenre(g, new Genre("B4", "Руководства"));
        addGenre(g, new Genre("B0", "Справочники"));

        g = new Genre("C", "Документальная литература");
        addGenre(g, new Genre("C1", "Биографии и Мемуары"));
        addGenre(g, new Genre("C2", "Публицистика"));
        addGenre(g, new Genre("C3", "Критика"));
        addGenre(g, new Genre("C4", "Искусство и Дизайн"));
        addGenre(g, new Genre("C5", "Документальная литература"));

        g = new Genre("D", "Религия и духовность");
        addGenre(g, new Genre("D1", "Религия"));
        addGenre(g, new Genre("D2", "Эзотерика"));
        addGenre(g, new Genre("D3", "Самосовершенствование"));
        addGenre(g, new Genre("D0", "Религиозная литература"));

        g = new Genre("E", "Юмор");
        addGenre(g, new Genre("E1", "Анекдоты"));
        addGenre(g, new Genre("E2", "Юмористическая проза"));
        addGenre(g, new Genre("E3", "Юмористические стихи"));
        addGenre(g, new Genre("E0", "Юмор"));

        g = new Genre("F", "Домоводство (Дом и семья)");
        addGenre(g, new Genre("F1", "Кулинария"));
        addGenre(g, new Genre("F2", "Домашние животные"));
        addGenre(g, new Genre("F3", "Хобби и ремесла"));
        addGenre(g, new Genre("F4", "Развлечения"));
        addGenre(g, new Genre("F5", "Здоровье"));
        addGenre(g, new Genre("F6", "Сад и огород"));
        addGenre(g, new Genre("F7", "Сделай сам"));
        addGenre(g, new Genre("F8", "Спорт"));
        addGenre(g, new Genre("F9", "Эротика, Секс"));
        addGenre(g, new Genre("F0", "Домоводство"));
        addGenre(g, new Genre("FA", "Путеводители"));

        g = new Genre("0", "Экономика и бизнес");
        addGenre(g, new Genre("01", "Поиск работы, карьера"));
        addGenre(g, new Genre("02", "Управление, подбор персонала"));
        addGenre(g, new Genre("03", "Маркетинг, реклама"));
        addGenre(g, new Genre("04", "Банковское дело"));
        addGenre(g, new Genre("05", "Ценные бумаги, инвестиции"));
        addGenre(g, new Genre("06", "Бухучет, налогообложение, аудит"));
        addGenre(g, new Genre("07", "Внешнеэкономическая деятельность"));
        addGenre(g, new Genre("00", "Экономика"));
        addGenre(g, new Genre("08", "Отраслевые издания"));
        addGenre(g, new Genre("09", "Корпоративная культура"));
        addGenre(g, new Genre("0A", "Личные финансы"));
        addGenre(g, new Genre("0B", "Недвижимость"));
        addGenre(g, new Genre("0C", "О бизнесе популярно"));
        addGenre(g, new Genre("0D", "Малый бизнес"));
        addGenre(g, new Genre("0E", "Делопроизводство"));
        addGenre(g, new Genre("0F", "Справочники по экономике"));

        g = new Genre("", "Без жанра");
        addGenre(g, new Genre("", "Без жанра"));
    }

    private void addGenre(Genre basicGenre, Genre childGenre) {
        List<Genre> children = fullList.get(basicGenre);
        if (children == null) {
            children = new ArrayList<>();
            fullList.put(basicGenre, children);
        }
        children.add(childGenre);
    }

    private DefaultTreeModel getTreeModel() {
        return (DefaultTreeModel) getModel();
    }

    public void clearNodes() {
        ((DefaultMutableTreeNode) getTreeModel().getRoot()).removeAllChildren();
        getTreeModel().reload();
    }

    public void fillTree() {
        clearNodes();
        if (filter.isEmpty()) {
            fillWithoutFilter();
        } else {
            fillFiltered();
        }
    }

    public void addFilter(String... filter) {
        for (String f : filter) {
            this.filter.add(f);
        }
    }

    public void clearFilter() {
        filter.clear();
    }

    private void fillWithoutFilter() {
        DefaultTreeModel model = getTreeModel();
        for (Genre genre : fullList.keySet()) {
            GenresTreeNode node = new GenresTreeNode(genre);
            ((DefaultMutableTreeNode) model.getRoot()).add(node);
            List<Genre> children = fullList.get(genre);
            for (Genre childGenre : children) {
                GenresTreeNode childNode = new GenresTreeNode(childGenre);
                node.add(childNode);
            }
        }
        model.reload();
    }

    private boolean checkIfGenreFiltered(Genre genre) {
        return filter.contains(genre.getId());
    }

    private void fillFiltered() {
        DefaultTreeModel model = getTreeModel();
        for (Genre genre : fullList.keySet()) {
            boolean flag = false;
            GenresTreeNode node = new GenresTreeNode(genre);
            if (checkIfGenreFiltered(genre)) {
                flag = true;
            }

            List<Genre> children = fullList.get(genre);
            for (Genre childGenre : children) {
                if (checkIfGenreFiltered(childGenre)) {
                    GenresTreeNode childNode = new GenresTreeNode(childGenre);
                    node.add(childNode);
                    flag = true;
                }
            }
            if (flag) {
                ((DefaultMutableTreeNode) model.getRoot()).add(node);
            }
        }
        model.reload();
    }
}